/*
 MNet - Network Library for Mobile Processing
 
 Copyright (c) 2005-2007 Francis Li
 Copyright (c) 2007-2008 Mary Jane Soft - Marlon J. Manrique
 	
 http://mobile.processing.org
 http://mjs.darkgreenmedia.com
 http://marlonj.darkgreenmedia.com	
 	
 This library is free software; you can redistribute it and/or
 modify it under the terms of the GNU Lesser General Public
 License as published by the Free Software Foundation; either
 version 2.1 of the License, or (at your option) any later version.
 
 This library is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 Lesser General Public License for more details.
 	
 You should have received a copy of the GNU Lesser General
 Public License along with this library; if not, write to the
 Free Software Foundation, Inc., 59 Temple Place, Suite 330,
 Boston, MA  02111-1307  USA
 	
 $Id: MNet.java 375 2008-02-28 14:39:27Z marlonj $

*/

import java.io.ByteArrayOutputStream;
import java.io.OutputStream;

import java.util.Vector;

import javax.microedition.io.Connector;
import javax.microedition.io.HttpConnection;

import processing.core.PClient;
import processing.core.PMIDlet;
import processing.core.PRequest;

/**
 * Network Client 
 *
 * This class is based on the oficial PClient class, only adds cookies 
 * support
 */
public class MClient extends PClient
{
  /**
   * Create a Network Client 
   *
   * @see PClient(PMIDlet,String)
   */
  public MClient(PMIDlet pMIDlet, String server)
  {
    super(pMIDlet,server);
  }

  /**
   * Create the request
   *
   * Overwritten version to create a MRequest instead a PRequest
   *
   * @see PClient#request(String,String,bte[])
   */
  protected PRequest request(String file, String contentType, byte[] bytes)
  {
    //// create url
    StringBuffer url = new StringBuffer();
    url.append("http://");
    url.append(server);
    if (port != 80) {
      url.append(":");
      url.append(port);
    }
    url.append(file);
    //// initiate request
    //// CHANGE : Create a MRequest 
    PRequest request = new MRequest(midlet, url.toString(), contentType, bytes);
    Thread t = new Thread(request);
    t.start();

    return request;	
  }
}

/**
 * Create a request with cookies support
 *
 * This class is based on the oficial PRequest class, if only adds cookies 
 * support
 */
public class MRequest extends PRequest
{
  /**
   * Cookies to send
   */
  private String[] cookies;

  /**
   * Create a request
   *
   * @see PRequest(PMIDlet,String,String,byte[])
   */
  public MRequest(PMIDlet pMIDlet, String url, String contentType, byte[] bytes)
  {
    super(pMIDlet,url,contentType,bytes,null);
  }

  /**
   * Retrive data 
   * 
   * Overwritten version to create a MRequest instead a PRequest
   */
  public void run() {
    OutputStream os = null;
    try {
      if (is == null) {
        //// open connection to server
        con = (HttpConnection) Connector.open(url);
        if (contentType != null) {
          con.setRequestMethod(HttpConnection.POST);
          con.setRequestProperty("Content-Type", contentType);
        } 
        else {
          con.setRequestMethod(HttpConnection.GET);
        }
        con.setRequestProperty("Connection", "close");
        /// CHANGE : Set cookies        
        if(cookies != null)
        {
          // Create a string with all the cookies separated by ;
          StringBuffer sb = new StringBuffer();
          for(int i=0; i<cookies.length; i++)
            sb.append(cookies[i] + ";");

          // Set Cookies
          con.setRequestProperty("cookie",sb.toString());
        }
        if (bytes != null) {
          os = con.openOutputStream();
          os.write(bytes);
          //// we can release the request bytes and reuse the reference
          bytes = null;
        }
        //// now, open inputstream, committing the post
        is = con.openInputStream();
        //// done, notify midlet
        boolean notify = false;
        synchronized (this) {
          if (state == STATE_OPENED) {
            state = STATE_CONNECTED;
            notify = true;
          }
        }
        if (notify) {
          midlet.enqueueLibraryEvent(this, EVENT_CONNECTED, null);
        }
      } 
      else {
        synchronized (this) {
          if (state == STATE_CONNECTED) {
            state = STATE_FETCHING;
          } 
          else {
            throw new Exception("Not connected.");
          }
        }
        //// read the response
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int bytesRead = is.read(buffer);
        while (bytesRead >= 0) {
          baos.write(buffer, 0, bytesRead);
          bytesRead = is.read(buffer);
        }
        buffer = null;
        buffer = baos.toByteArray();
        //// done, notify midlet
        boolean notify = false;
        synchronized (this) {
          if (state == STATE_FETCHING) {
            state = STATE_DONE;
            notify = true;
          }
        }
        if (notify) {
          midlet.enqueueLibraryEvent(this, EVENT_DONE, buffer);
        }
      }
    } 
    catch (Exception e) {
      boolean notify = false;
      synchronized (this) {
        if ((state == STATE_CONNECTED) || (state == STATE_FETCHING)) {
          notify = true;
        }
      }
      close();
      if (notify) {
        synchronized (this) {
          state = STATE_ERROR;
        }
        midlet.enqueueLibraryEvent(this, EVENT_ERROR, e.getMessage());
      }
    } 
    finally {
      if (os != null) {
        try {
          os.close();
        } 
        catch (Exception e) { 
        }
        os = null;
      }            
    }
  }	

  /**
   * Return the current cookies in the response of the sever
   *
   * @return List of cookies
   */
  public String[] cookies()
  {
    // Create a cookie list
    Vector cookies = new Vector();

    // Headers
    String key;
    String value;

    // Count headers
    int counter = 0;

    try
    {		
      // Get all the headers, one by one 
      while((key = con.getHeaderFieldKey(counter)) != null)
      {
        // Get the header key and lower case to avoid conflicts
        key = key.toLowerCase();

        // If is a cookie, get the value and add to the cookies list
        if(key.equals("set-cookie"))
        {
          value = con.getHeaderField(counter);
          cookies.addElement(value.substring(0,value.indexOf(';')));
        }

        // Next header
        counter++;
      }
    }
    catch(Exception e)
    {
      e.printStackTrace();
    }

    // Copy the list to an array
    String[] array = new String[cookies.size()];
    cookies.copyInto(array);

    // Return the array of of cookies
    return array;
  }

  /**
   * Set the cookies to sen with the request 
   *
   * @param cookies Cookies to send
   */
  public void cookies(String[] cookies)
  {
    this.cookies = cookies;
  }    
}
